This patch adds support for newer versions of DRBD.

Submitted upstream: <https://github.com/ganeti/ganeti/pull/1496>.

diff --git a/lib/storage/drbd.py b/lib/storage/drbd.py
--- a/lib/storage/drbd.py
+++ b/lib/storage/drbd.py
@@ -315,6 +315,13 @@ class DRBD8Dev(base.BlockDev):
     """
     return self._show_info_cls.GetDevInfo(self._GetShowData(minor))
 
+  @staticmethod
+  def _NeedsLocalSyncerParams():
+    # For DRBD >= 8.4, syncer init must be done after local, not in net.
+    info = DRBD8.GetProcInfo()
+    version = info.GetVersion()
+    return version["k_minor"] >= 4
+
   def _MatchesLocal(self, info):
     """Test if our local config matches with an existing device.
 
@@ -397,6 +404,20 @@ class DRBD8Dev(base.BlockDev):
         base.ThrowError("drbd%d: can't attach local disk: %s",
                         minor, result.output)
 
+    def _WaitForMinorSyncParams():
+      """Call _SetMinorSyncParams and raise RetryAgain on errors.
+      """
+      if self._SetMinorSyncParams(minor, self.params):
+        raise utils.RetryAgain()
+
+    if self._NeedsLocalSyncerParams():
+      # Retry because disk config for DRBD resource may be still uninitialized.
+      try:
+        utils.Retry(_WaitForMinorSyncParams, 1.0, 5.0)
+      except utils.RetryTimeout as e:
+        base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
+                        (minor, utils.CommaJoin(e.args[0])))
+
   def _AssembleNet(self, minor, net_info, dual_pri=False, hmac=None,
                    secret=None):
     """Configure the network part of the device.
@@ -432,21 +453,24 @@ class DRBD8Dev(base.BlockDev):
     # sync speed only after setting up both sides can race with DRBD
     # connecting, hence we set it here before telling DRBD anything
     # about its peer.
-    sync_errors = self._SetMinorSyncParams(minor, self.params)
-    if sync_errors:
-      base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
-                      (minor, utils.CommaJoin(sync_errors)))
+
+    if not self._NeedsLocalSyncerParams():
+      sync_errors = self._SetMinorSyncParams(minor, self.params)
+      if sync_errors:
+        base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
+                        (minor, utils.CommaJoin(sync_errors)))
 
     family = self._GetNetFamily(minor, lhost, rhost)
 
-    cmd = self._cmd_gen.GenNetInitCmd(minor, family, lhost, lport,
+    cmds = self._cmd_gen.GenNetInitCmds(minor, family, lhost, lport,
                                       rhost, rport, protocol,
                                       dual_pri, hmac, secret, self.params)
 
-    result = utils.RunCmd(cmd)
-    if result.failed:
-      base.ThrowError("drbd%d: can't setup network: %s - %s",
-                      minor, result.fail_reason, result.output)
+    for cmd in cmds:
+      result = utils.RunCmd(cmd)
+      if result.failed:
+        base.ThrowError("drbd%d: can't setup network: %s - %s",
+                         minor, result.fail_reason, result.output)
 
     def _CheckNetworkConfig():
       info = self._GetShowInfo(minor)
@@ -463,19 +487,20 @@ class DRBD8Dev(base.BlockDev):
       base.ThrowError("drbd%d: timeout while configuring network", minor)
 
     # Once the assembly is over, try to set the synchronization parameters
-    try:
-      # The minor may not have been set yet, requiring us to set it at least
-      # temporarily
-      old_minor = self.minor
-      self._SetFromMinor(minor)
-      sync_errors = self.SetSyncParams(self.params)
-      if sync_errors:
-        base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
-                        (self.minor, utils.CommaJoin(sync_errors)))
-    finally:
-      # Undo the change, regardless of whether it will have to be done again
-      # soon
-      self._SetFromMinor(old_minor)
+    if not self._NeedsLocalSyncerParams():
+      try:
+        # The minor may not have been set yet, requiring us to set it at least
+        # temporarily
+        old_minor = self.minor
+        self._SetFromMinor(minor)
+        sync_errors = self.SetSyncParams(self.params)
+        if sync_errors:
+          base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
+                          (self.minor, utils.CommaJoin(sync_errors)))
+      finally:
+        # Undo the change, regardless of whether it will have to be done again
+        # soon
+        self._SetFromMinor(old_minor)
 
   @staticmethod
   def _GetNetFamily(minor, lhost, rhost):
diff --git a/lib/storage/drbd_cmdgen.py b/lib/storage/drbd_cmdgen.py
--- a/lib/storage/drbd_cmdgen.py
+++ b/lib/storage/drbd_cmdgen.py
@@ -56,7 +56,7 @@ class BaseDRBDCmdGenerator(object):
   def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
     raise NotImplementedError
 
-  def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol,
+  def GenNetInitCmds(self, minor, family, lhost, lport, rhost, rport, protocol,
                     dual_pri, hmac, secret, params):
     raise NotImplementedError
 
@@ -138,7 +138,7 @@ class DRBD83CmdGenerator(BaseDRBDCmdGenerator):
 
     return [args]
 
-  def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol,
+  def GenNetInitCmds(self, minor, family, lhost, lport, rhost, rport, protocol,
                     dual_pri, hmac, secret, params):
     args = ["drbdsetup", self._DevPath(minor), "net",
             "%s:%s:%s" % (family, lhost, lport),
@@ -155,7 +155,7 @@ class DRBD83CmdGenerator(BaseDRBDCmdGenerator):
     if params[constants.LDP_NET_CUSTOM]:
       args.extend(shlex.split(params[constants.LDP_NET_CUSTOM]))
 
-    return args
+    return [args]
 
   def GenSyncParamsCmd(self, minor, params):
     args = ["drbdsetup", self._DevPath(minor), "syncer"]
@@ -345,8 +345,14 @@ class DRBD84CmdGenerator(BaseDRBDCmdGenerator):
 
     return cmds
 
-  def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol,
+  def GenNetInitCmds(self, minor, family, lhost, lport, rhost, rport, protocol,
                     dual_pri, hmac, secret, params):
+    cmds = []
+
+    cmds.append(["drbdsetup", "new-resource", self._GetResource(minor)])
+    cmds.append(["drbdsetup", "new-minor", self._GetResource(minor),
+                 str(minor), "0"])
+
     args = ["drbdsetup", "connect", self._GetResource(minor),
             "%s:%s:%s" % (family, lhost, lport),
             "%s:%s:%s" % (family, rhost, rport),
@@ -362,7 +368,8 @@ class DRBD84CmdGenerator(BaseDRBDCmdGenerator):
     if params[constants.LDP_NET_CUSTOM]:
       args.extend(shlex.split(params[constants.LDP_NET_CUSTOM]))
 
-    return args
+    cmds.append(args)
+    return cmds
 
   def GenSyncParamsCmd(self, minor, params):
     args = ["drbdsetup", "disk-options", minor]
